#include<iostream>
#include<vector>
#include<queue>
#include<unistd.h>
#include<pthread.h>
using namespace std;

#define MAX_QUEUE 5

template <class T>
class BlockQueue{//线程安全的任务队列
public:
    BlockQueue(int capacity=MAX_QUEUE)
    :_capacity(capacity)
    {pthread_mutex_init(&_mutex,NULL);
     pthread_cond_init(&_cond_pro,NULL);
     pthread_cond_init(&_cond_cus,NULL);}
    bool Push(const T& data){//生产线程
        //队列满了就要阻塞，不能继续入队
        pthread_mutex_lock(&_mutex);
        while(_queue.size()==_capacity){
            pthread_cond_wait(&_cond_pro,&_mutex);
        }
        _queue.push(data);
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_cond_cus);
        return true;
    }
    bool Pop(T* data){//消费线程
        //队列为空则阻塞
        pthread_mutex_lock(&_mutex);
        while(_queue.empty()==true){
            pthread_cond_wait(&_cond_cus,&_mutex);
        }
        *data=_queue.front();
        _queue.pop();
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_cond_pro);
        return true;
    }
    ~BlockQueue(){
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond_pro);
    pthread_cond_destroy(&_cond_cus);
    }
private:
    queue<T> _queue;
    int _capacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond_pro;
    pthread_cond_t _cond_cus; 
};
template <class T>
class ThreadTask{//任务类
private:
typedef void(*handler_t)(T);//别名为handler_t的指针类型
    T _data;//要处理的数据
    handler_t _handler;//处理数据的方法
public:
    ThreadTask(){}
    ThreadTask(T data,handler_t handler)
    :_data(data),_handler(handler){}
    void run(){
        return _handler(_data);
    }
};
template<class T>
class ThreadPool{//线程池
private:
    int _thread_max;
    vector<pthread_t> _tid;//指定数量的线程
    BlockQueue<ThreadTask<T>> _queue;//线程安全的任务队列
private:
    static void *thread_entry(void *arg){//静态函数没有this指针
        ThreadPool *pool=(ThreadPool*)arg;
        while(1){
            ThreadTask<T> task;
            pool->_queue.Pop(&task);
            task.run();
        }
        return NULL;
    }
public:
    ThreadPool(int mt,int mq)
    :_thread_max(mt),_queue(mq){
        pthread_t tid;
        int ret;
        for(int i=0;i<mt;i++){
            ret=pthread_create(&tid,NULL,thread_entry,this);
            if(ret!=0){
                printf("create thread failed!");
                exit(-1);
            }
            _tid.push_back(tid);
        }
    }
    void Join(){
        for(int i=0;i<_tid.size();i++){
            pthread_join(_tid[i],NULL);
        }
    }
    bool Push(const ThreadTask<T> &task){
        _queue.Push(task);
        return true;
    }
};
void test(int data){
    printf("%p --- get data:%d\n",(void*)pthread_self(),data);
    int sec=(data % 5)+1;
    sleep(sec);
}
int main(){
    ThreadPool<int> pool(5,10);
    for(int i=0;i<10;i++){
        ThreadTask<int> task(i,test);
        pool.Push(task);
    }
    pool.Join();
    return 0;
}
